package io.github.talelin.latticy.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.github.talelin.latticy.common.cache.RedisUtil;
import io.github.talelin.latticy.common.constant.WmsConstant;
import io.github.talelin.latticy.common.mybatis.Page;
import io.github.talelin.latticy.dto.stock.BatchStockDTO;
import io.github.talelin.latticy.dto.stock.BatchStockPageDTO;
import io.github.talelin.latticy.dto.stock.BatchStockVO;
import io.github.talelin.latticy.mapper.BatchStockMapper;
import io.github.talelin.latticy.model.BatchStockDO;
import io.github.talelin.latticy.model.BatchStockLogDO;
import io.github.talelin.latticy.model.StockDO;
import io.github.talelin.latticy.service.BatchStockLogService;
import io.github.talelin.latticy.service.BatchStockService;
import io.github.talelin.latticy.service.StockService;
import io.github.talelin.latticy.util.PageHelpUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.Objects;
import java.util.function.BiPredicate;

/**
 * <p>
 * 批次库存 服务实现类
 * </p>
 *
 * @author generator@wulongbo
 * @since 2022-06-28
 */
@Service
public class BatchStockServiceImpl extends ServiceImpl<BatchStockMapper, BatchStockDO> implements BatchStockService {


    @Resource
    private RedisUtil redisUtil;

    @Resource
    private StockService stockService;

    @Resource
    private BatchStockLogService batchStockLogService;

    private final BiPredicate<Long,Long> isPutAwayOverage=(putInStock, putAway)->putInStock.compareTo(putAway)>=0;

    @Override
    public IPage<BatchStockVO> getBatchStockBySku(BatchStockPageDTO batchStockPageDTO) {
        IPage<BatchStockDO> batchStockDOPage = this.baseMapper.selectPage(new Page<>(batchStockPageDTO.getCurrPage(), batchStockPageDTO.getPageSize()), new LambdaQueryWrapper<BatchStockDO>().eq(StrUtil.isNotEmpty(batchStockPageDTO.getWarehouseCode()), BatchStockDO::getWarehouseCode, batchStockPageDTO.getWarehouseCode()).like(StrUtil.isNotEmpty(batchStockPageDTO.getCustomerCode()), BatchStockDO::getCustomerCode, batchStockPageDTO.getCustomerCode()).like(StrUtil.isNotEmpty(batchStockPageDTO.getSku()), BatchStockDO::getSku, batchStockPageDTO.getSku()).between(Objects.nonNull(batchStockPageDTO.getCreateTimeStart()) && Objects.nonNull(batchStockPageDTO.getCreateTimeEnd()), BatchStockDO::getCreateTime, batchStockPageDTO.getCreateTimeStart(), batchStockPageDTO.getCreateTimeEnd()));
        IPage<BatchStockVO> resultPage = PageHelpUtil.convertPage(batchStockDOPage, BatchStockVO.class);
        if (CollUtil.isEmpty(resultPage.getRecords())) {
            return resultPage;
        }
        Date date = new Date();
        for (BatchStockVO batchStockVO : resultPage.getRecords()) {
            //库龄计算
            String stockAge = DateUtil.formatBetween(batchStockVO.getLibraryTime(), date, BetweenFormatter.Level.DAY);
            batchStockVO.setStockAge(stockAge);
        }
        return resultPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchStockSave(BatchStockDO batchStockDO) {
        Assert.notNull(batchStockDO, "18510");
        String operateNo = "QC" + DateUtil.format(new Date(), "yyyyMMdd");
        long incr = redisUtil.incr(operateNo, 1);
        if (incr == 1) {
            redisUtil.expire(operateNo, 60 * 60 * 24);
        }
        operateNo = operateNo + String.format("%04d", incr);
        batchStockDO.setOperateNo(operateNo);

        Assert.isTrue(baseMapper.insert(batchStockDO) > 0, "18511");

        StockDO stock = stockService.getStockByWarehouseCodeAndCustomerCodeAndSku(batchStockDO.getWarehouseCode(), batchStockDO.getCustomerCode(), batchStockDO.getSku());
        Assert.notNull(stock, "18514");
        boolean test = isPutAwayOverage.test(stock.getOnThePutAway(), batchStockDO.getQuantity());
        Assert.isTrue(test, "18517");
        // 存在 累加
        StockDO stockDO = new StockDO();
        stockDO.setId(stock.getId());
        stockDO.setAvailableStock(stock.getAvailableStock() + batchStockDO.getQuantity());
        stockDO.setOnThePutAway(stock.getOnThePutAway() - batchStockDO.getQuantity());
        stockDO.setUpdateTime(batchStockDO.getCreateTime());
        Assert.isTrue(stockService.updateById(stockDO), "18512!");

        // 新增批次库存操作日志
        BatchStockLogDO batchStockLogDO = new BatchStockLogDO();
        batchStockLogDO.setOperateNo(operateNo);
        batchStockLogDO.setWarehouseCode(batchStockDO.getWarehouseCode());
        batchStockLogDO.setSku(batchStockDO.getSku());
        batchStockLogDO.setSkuName(batchStockDO.getSkuName());
        batchStockLogDO.setLocation(batchStockDO.getLocation());
        batchStockLogDO.setChangeQuantity(batchStockDO.getQuantity());
        batchStockLogDO.setBeforeChange(0L);
        batchStockLogDO.setAfterChange(batchStockDO.getQuantity());
        batchStockLogDO.setOrderNo(batchStockDO.getOrderNo());
        batchStockLogDO.setOperateType(WmsConstant.OPERATE_TYPE_PUT_AWAY);
        batchStockLogDO.setCreateTime(batchStockDO.getCreateTime());
        Assert.isTrue(batchStockLogService.save(batchStockLogDO), "18513");
    }

    @Override
    public void resizeLibraryAge(BatchStockDTO batchStockDO) {
        BatchStockDO batchStock = batchStock(batchStockDO);
        BatchStockDO batchStockVo = new BatchStockDO();
        batchStockVo.setId(batchStock.getId());
        batchStockVo.setLibraryTime(batchStockDO.getLibraryTime());
        Assert.isTrue(this.updateById(batchStockVo),"18520");
    }

    @Override
    public void resizeStockNum(BatchStockDTO batchStockDO) {
        BatchStockDO batchStock = batchStock(batchStockDO);
        BatchStockDO batchStockVo = new BatchStockDO();
        batchStockVo.setId(batchStock.getId());
        batchStockVo.setQuantity(batchStockDO.getQuantity());
        Assert.isTrue(this.updateById(batchStockVo),"18520");
    }

    /**
     * 获取批次库存信息
     * @param batchStockDO
     * @return
     */
    private BatchStockDO batchStock(BatchStockDTO batchStockDO) {
        BatchStockDO batchStock = this.getOne(new LambdaQueryWrapper<BatchStockDO>()
                .eq(BatchStockDO::getPutAwayBatchNo, batchStockDO.getPutAwayBatchNo())
                .eq(BatchStockDO::getSku, batchStockDO.getSku())
                .eq(BatchStockDO::getWarehouseCode, batchStockDO.getWarehouseCode())
                .eq(BatchStockDO::getOrderNo, batchStockDO.getOrderNo())
                .eq(batchStockDO.getLocationId() != null, BatchStockDO::getLocationId, batchStockDO.getLocationId())
                .eq(StringUtils.isNoneBlank(batchStockDO.getCustomerCode()), BatchStockDO::getCustomerCode, batchStockDO.getCustomerCode()));
        Assert.notNull(batchStock, "18712");
        return batchStock;
    }
}
